﻿using BusinessLayer;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Script.Services;
using System.Web.Security;
using System.Web.Services;
using System.Web.Script.Serialization;
using BusinessLayer.BLServerReference;
using System.Diagnostics;
using System.Reflection;
using WebFrontEnd.Helpers;
using System.Configuration;
namespace WebFrontEnd.Services
{
    /// <summary>
    /// Summary description for GuestsService
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    [System.Web.Script.Services.ScriptService]
    public class GuestsService : System.Web.Services.WebService
    {

        #region Private Members
        private IBL _bl;
        private User _currentUser;
        private JavaScriptSerializer _json;
        #endregion

        #region Private Properties
        private IBL BL 
        {
            //Lazy Loading
            get
            {
                if (_bl == null)
                {
                    _bl = BusinessLayerFactory.GetCurrentBusinessLayer(ConfigurationManager.AppSettings.Get("DomainName"));
                }
                return _bl;
            }
        }

        private User CurrentUser
        {
            //Lazy Loading
            get
            {
                if (_currentUser == null)
                {
                    _currentUser = GetCurrentUser();
                }
                return _currentUser;
            }
        }

        private JavaScriptSerializer JSON
        {
            get
            {
                if (_json == null)
                {
                    _json = new JavaScriptSerializer();
                }
                return _json;
            }
        }
        #endregion

        #region Private Methods
        protected User GetCurrentUser()
        {
            return BL.GetUserByEmail(User.Identity.Name);
        }

        protected BusinessLayer.BLServerReference.Event CheckEventID(int eventID)
        {
            var ev = BL.GetEventById(eventID);
            return ev.UserID == CurrentUser.ID ? ev : null;
        }
        #endregion

        #region Web Methods
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public string AllGuests()
        {
            IEnumerable<Guest> guestList = BL.GetUsersGuests(CurrentUser).ToList();
            foreach (var item in guestList)
            {
                item.User = null;
            }
            return JSON.Serialize(guestList);
        }

        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public string GetGuestsInvites(int guestid)
        {
            Guest g = BL.GetGuestByID(guestid);
            if (g != null && g.UserID == CurrentUser.ID)
            {
                IEnumerable<Invite> invites = BL.GetGuestsInvites(g);
                return JSON.Serialize(invites);
            }
            return "ERROR";
        }

        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public string SearchForGuests(string keyword)
        {
            var ret = BL.SearchForGuests(keyword, CurrentUser.ID);
            return JSON.Serialize(ret);
        }

        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public string SearchForNonInvitedGuests(string keyword,int eventID)
        {
            var ret = BL.SearchForNonInvitedGuests(keyword,eventID, CurrentUser.ID);
            return JSON.Serialize(ret);
        }

        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public object InviteGuestToEvent(int guestID, int eventID,int additionalGuests)
        {
            var ev = BL.GetEventById(eventID);
            Guest guest = BL.GetGuestByID(guestID);
            if (ev == null || guest == null || ev.UserID != CurrentUser.ID || guest.UserID != CurrentUser.ID)
            {
                return new
                {
                    Result = "ERROR",
                    Message = "Server Error"
                };
            }
            Invite invite = new Invite();
            invite.GuestID = guest.ID;
            invite.EventID = ev.ID;
            invite.AdditionalInvitedGuests = additionalGuests;
            var report = BL.CreateInvite(invite);
            if (!report.Valid)
            {
                return new
                {
                    Result = "ERROR",
                    Message = report.Message
                };
            }
            return new { Result = "OK" };
        }
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public object RSVPGuestToEvent(int guestID, int eventID,bool rsvp,int numReserved)
        {
            var ev = BL.GetEventById(eventID);
            Guest guest = BL.GetGuestByID(guestID);
            if (ev == null || guest == null || ev.UserID != CurrentUser.ID || guest.UserID != CurrentUser.ID)
            {
                return new
                {
                    Result = "ERROR",
                    Message = "There was an error in the communication."
                };
            }
            Invite invite = BL.GetInviteByEventAndGuest(ev, guest);
            invite.RSVPd = rsvp;
            if (numReserved > invite.AdditionalInvitedGuests + (invite.Guest.Couple ? 2 : 1))
            {
                return new { 
                    Result = "ERROR",
                    Message = "Parameter error: numReserved"
                };
            }
            if (rsvp)
            {
                invite.ReservedGuests = numReserved;
            }
            if (BL.UpdateInvite(invite) != null)
            {
                return new
                {
                    Result = "OK"
                };
            }
            return new
            {
                Result = "ERROR",
                Message = "Server Error"
            };
        }
        
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public object JtableDeleteInvite(Dictionary<string,int> ID)
        {
            var ev = CheckEventID(ID["EventID"]);
            if (ev == null)
            {
                return new
                {
                    Result = "ERROR",
                    Message = "You do not have permission to delete that event."
                };
            }
            if (BL.DeleteInvite(ID["EventID"], ID["InviteID"], ID["GuestID"]))
            {
                return new
                {
                    Result = "OK"
                };
            }
            return new
            {
                Result = "ERROR",
                Message = "You do not have permission to delete that event."
            };
        }

        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public object JtableListEventsGuests(int eventID,string jtStartIndex,string jtPageSize,string jtSorting)
        {            
            var ev = CheckEventID(eventID);
            if (ev == null)
            {
                return new { 
                    Result = "ERROR",
                    Message = "You do not have permission to access that event."
                };
            }
            int startIndex, pageSize;
            int.TryParse(jtStartIndex, out startIndex);
            int.TryParse(jtPageSize, out pageSize);
            List<object> retList = new List<object>();
            
            var invites = BL.GetInvitesByEvent(ev);
            int total = invites.Count();
            string sortColumn = jtSorting.Split(' ')[0];
            string sortWay = jtSorting.Split(' ')[1];

            switch (sortColumn)
            {
                case "Email":
                    if (sortWay == "ASC")
                        invites = invites.OrderBy(i => i.Guest.Email).Page(startIndex, pageSize);
                    else
                        invites = invites.OrderByDescending(i => i.Guest.Email).Page(startIndex, pageSize);
                    break;
                case "Name":
                    if (sortWay == "ASC")
                        invites = invites.OrderBy(i => i.Guest.LastName).Page(startIndex, pageSize);
                    else
                        invites = invites.OrderByDescending(i => i.Guest.LastName).Page(startIndex, pageSize);
                    break;
                case "RSVP":
                    if (sortWay == "ASC")
                        invites = invites.OrderBy(i => i.RSVPd).Page(startIndex, pageSize);
                    else
                        invites = invites.OrderByDescending(i => i.RSVPd).Page(startIndex, pageSize);
                    break;
                case "Gift":
                    if (sortWay == "ASC")
                        invites = invites.OrderBy(i => i.Gift == null).Page(startIndex, pageSize);
                    else
                        invites = invites.OrderByDescending(i => i.Gift == null).Page(startIndex, pageSize);
                    break;
                default:
                    if (sortWay == "ASC")
                        invites = invites.OrderBy(i => i.Guest.Email).Page(startIndex, pageSize);
                    else
                        invites = invites.OrderByDescending(i => i.Guest.Email).Page(startIndex, pageSize);                    
                    break;
            }
            foreach (var invite in invites)
            {
                string giftType = "";
                if (invite.Gift != null)
                {
                    giftType = invite.Gift.GetType().Name;
                }
                retList.Add(new { 
                    ID = new {
                        EventID = invite.EventID,
                        InviteID = invite.ID,
                        GuestID = invite.GuestID
                    },
                    Name = invite.Guest.CombinedName(),
                    Email = invite.Guest.Email,
                    GuestID = invite.Guest.ID,
                    RSVPd = invite.RSVPd,
                    ReservedGuests = invite.ReservedGuests,
                    TotalInvited = invite.AdditionalInvitedGuests + (invite.Guest.Couple ? 2 : 1),
                    Gift = invite.Gift,
                    GiftType = giftType
                });
            }

            return new { 
                Result = "OK", 
                Records = retList,
                TotalRecordCount = total
            };
        }
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public object UpdateGift(string giftType, string description, string amount, string currency, string depositdate, string name, string storebought, int guestID, int eventID)
        {
            var ev = BL.GetEventById(eventID);
            Guest guest = BL.GetGuestByID(guestID);
            if (ev == null || guest == null || ev.UserID != CurrentUser.ID || guest.UserID != CurrentUser.ID)
            {
                return new
                {
                    Result = "ERROR",
                    Message = "There was an error in the communication."
                };
            }
            try
            {
                Invite currentInvite = BL.GetInviteByEventAndGuest(ev, guest);
                Gift CurrentGift = currentInvite.Gift;
                string currentGiftType = CurrentGift != null ? CurrentGift.GetType().Name : "";
                switch (giftType)
                {
                    case "Cash":
                        if ("Cash" != currentGiftType)
                        {
                            CurrentGift = new Cash();
                        }
                        Cash c = (Cash)CurrentGift;
                        c.Amount = decimal.Parse(amount);
                        c.Currency = (Currency)Enum.Parse(typeof(Currency), currency);
                        c.Description = description;
                        break;
                    case "Check":
                        if ("Check" != currentGiftType)
                        {
                            CurrentGift = new Check();
                        }
                        Check check = (Check)CurrentGift;
                        check.Amount = decimal.Parse(amount);
                        check.Currency = (Currency)Enum.Parse(typeof(Currency), currency);
                        check.Description = description;
                        if (string.IsNullOrEmpty(depositdate))
                        {
                            check.DepositDate = null;
                        }
                        else
                        {
                            check.DepositDate = DateTime.Parse(depositdate);
                        }
                        break;
                    case "GiftItem":
                        if ("GiftItem" != currentGiftType)
                        {
                            CurrentGift = new GiftItem();
                        }
                        GiftItem giftItem = (GiftItem)CurrentGift;
                        giftItem.Description = description;
                        giftItem.Name = name;
                        giftItem.StoreBought = storebought;
                        break;
                    default:
                        break;
                }
                if (currentGiftType == "")
                {
                    currentInvite.GiftID = null;
                }
                else
                {
                    CurrentGift.ID = currentInvite.GiftID.Value;
                }
                currentInvite.Gift = CurrentGift;
                BL.UpdateInvite(currentInvite);
                return new
                {
                    Result = "OK"
                };
            }
            catch (Exception ex)
            {
                return new
                {
                    Result = "Error",
                    Message = "There was an error with your data."
                };
            }
        }
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public object JtableGuestControlPanelMain(string searchString, string jtStartIndex, string jtPageSize, string jtSorting)
        {
            string sortColumn = jtSorting.Split(' ')[0];
            string sortWay = jtSorting.Split(' ')[1];
            int startIndex, pageSize;
            int.TryParse(jtStartIndex, out startIndex);
            int.TryParse(jtPageSize, out pageSize);

            var user = GetCurrentUser();
            int totalrecordcount = 0;
            List<object> retList = new List<object>();
            IEnumerable<Guest> guests;
            if (searchString == "")
            {
                guests = BL.GetUsersGuests(user);
                totalrecordcount = guests.Count();

            }
            else
            {
                guests = BL.SearchForGuests(searchString, user.ID);
                totalrecordcount = guests.Count();
            }

            switch (sortColumn)
            {
                case "Email":
                    if (sortWay == "ASC")
                        guests = guests.OrderBy(g => g.Email).Page(startIndex, pageSize);
                    else
                        guests = guests.OrderByDescending(g => g.Email).Page(startIndex, pageSize);
                    break;
                case "Name":
                    if (sortWay == "ASC")
                        guests = guests.OrderBy(g => g.LastName).Page(startIndex, pageSize);
                    else
                        guests = guests.OrderByDescending(g => g.LastName).Page(startIndex, pageSize);
                    break;
                default:
                    if (sortWay == "ASC")
                        guests = guests.OrderBy(g => g.Email).Page(startIndex, pageSize);
                    else
                        guests = guests.OrderByDescending(g => g.Email).Page(startIndex, pageSize);
                    break;
            }
            foreach (var guest in guests)
            {
                retList.Add(new
                {
                    GuestID = guest.ID,
                    Name = guest.CombinedName(),
                    Email = guest.Email,
                    AvgGift = BL.GetAverageGuestGifts(guest),
                    Address = guest.AddressDisplay()
                });
            }
            return new
            {
                Result = "OK",
                Records = retList,
                TotalRecordCount = totalrecordcount
            };
        }

        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public object JtableGuestControlPanelChild(int guestID)
        {
            var guest = BL.GetGuestByID(guestID);
            var invites = BL.GetGuestsInvites(guest);
            List<object> retList = new List<object>();
            foreach (var invite in invites)
            {
                retList.Add(new { 
                    ID = invite.ID,
                    EventName = invite.Event.Name
                });
            }
            return new
            {
                Result = "OK",
                Records = retList
            };
        }

        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public object ListUsers(string jtStartIndex, string jtPageSize)//, string jtSorting)
        {
            if (CurrentUser.Role != Role.Admin)
            {
                return new { Result = "ERROR", Message = "You do not have permission to view this." };
            }
            var users = BL.GetAllUsers().ToList();
            List<object> users2 = new List<object>();
            foreach (var user in users)
            {
                users2.Add(new
                {
                    ID = user.ID,
                    FirstName = user.FirstName,
                    LastName = user.LastName,
                    Email = user.Email,
                    Role = user.Role
                });
            }
            return new { Result = "OK", Records = users2.ToArray(), TotalRecordCount = users.Count };
        }
        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public object DeleteUser(int ID)
        {
            var user = BL.GetUserByID(ID);
            if (user.Role == Role.Admin)
            {
                return new { Result = "ERROR", Message = "You cannot delete an Admin" };
            }
            try
            {
                BL.DeleteUser(user);
                return new { Result = "OK" };
            }
            catch (Exception ex)
            {
                return new { Result = "ERROR", Message = ex.Message };
            }
        }

        [WebMethod]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]     
        public object ChangePrivilege(int id)
        {
            var currentUser = GetCurrentUser();
            if (currentUser.ID == id)
            {
                return new { Result = "ERROR",Message = "You can't change your own privilege."};
            }
            var user = BL.GetUserByID(id);
            if (user != null)
            {
                user.Role = user.Role == Role.Admin ? Role.User : Role.Admin;
                BL.UpdateUser(user);
                return new { Result = "OK" };
            }
            else
            {
                return new { Result = "ERROR", Message = "That user does not exist" };
            }
        }

        #endregion
    }
}
